Engine.Line = function(start, end)
{
	this.start = start;
	this.vector = end.minus(start);
}

Engine.Line.prototype.inLeft = function(x,y){
    
	var newVector = (new Engine.Vector2(x,y)).minus(this.start);
	return (this.vector.y * newVector.x - this.vector.x * newVector.y) >= 0;
}

Engine.Triangle = function(vertices, normals, uv){
   this.vertices = vertices;
   this.normals = normals;
   this.uv = uv;
}

Engine.Triangle.prototype = (function(){
    var lines;
    var f = function (a,b,x,y,points)
    {
    	var temp = (points[a].y - points[b].y) * x + 
    			   (points[b].x - points[a].x) * y +
    			    points[a].x * points[b].y -
    				points[b].x * points[a].y;
    	return temp;
    };
    
    return {
        center : function(){
            return this.vertices[0].plus(this.vertices[1]).plus(this.vertices[2]).divide(3);
        },
        coecients : function(x,y,points){
            return {
        		a: f(1,2,x,y,points)/ f(1,2,points[0].x,points[0].y,points),
        		b: f(2,0,x,y,points)/ f(2,0,points[1].x,points[1].y,points),
        		r: f(0,1,x,y,points)/ f(0,1,points[2].x,points[2].y,points)
        	};
        },
        
        coecients3D : function(px,p0,p1,p2){
            var d = p0.x*p1.y*p2.z-p0.x*p1.z*p2.y-p0.y*p1.x*p2.z+p0.y*p1.z*p2.x+p0.z*p1.x*p2.y-p0.z*p1.y*p2.x;
            if(d == 0){
                var list = [];
                list.push(p0);
                list.push(p1);
                list.push(p2);
                return this.coecients(px.x,px.y,list);
            }
            return {
                a: (p1.x*p2.y*px.z-p1.x*p2.z*px.y-p1.y*p2.x*px.z+p1.y*p2.z*px.x+p1.z*p2.x*px.y-p1.z*p2.y*px.x)/d,
                b: -(p0.x*p2.y*px.z-p0.x*p2.z*px.y-p0.y*p2.x*px.z+p0.y*p2.z*px.x+p0.z*p2.x*px.y-p0.z*p2.y*px.x)/d,
                r: (p0.x*p1.y*px.z-p0.x*p1.z*px.y-p0.y*p1.x*px.z+p0.y*p1.z*px.x+p0.z*p1.x*px.y-p0.z*p1.y*px.x)/d
            };
        },
        interpolateZ : function(x,y){
        	var coe = this.coecients(x,y,this.sv);
        	return  this.sv[0].z * coe.a + this.sv[1].z * coe.b + this.sv[2].z * coe.r;
        },
        isInside : function (x,y){
            for(var i = 0; i < 3; i++){
        		if(!lines[i].inLeft(x,y))
        			return false;
        	}
        	return true;
        },
        begin : function (m2s,m2c,m2cn){
            var temp;
            this.cn = [];
            for(var i=0;i<3;i++){
                temp = m2cn.multiplyVector(this.normals[i]);
                this.cn.push(new Engine.Vector3(temp.x / temp.w,temp.y / temp.w,temp.z / temp.w));
            }
            
            this.sv = [];
            for(var i=0;i<3;i++){
                temp = m2s.multiplyVector(this.vertices[i]);
                this.sv.push(new Engine.Vector3(temp.x / temp.w,temp.y / temp.w,temp.z / temp.w));
            }
            
            this.cv = [];
            for(var i=0;i<3;i++){
                temp = m2c.multiplyVector(this.vertices[i]);
                this.cv.push(new Engine.Vector3(temp.x / temp.w,temp.y / temp.w,temp.z / temp.w));
            }

            this.top = this.sv[0].y;
        	this.bottom = this.sv[0].y;
        	this.left = this.sv[0].x;
        	this.right = this.sv[0].x;

        	for(var i = 1; i < 3; i++){
        		if(this.sv[i].x < this.left)
        			this.left = this.sv[i].x;
        		if(this.sv[i].x > this.right)
        			this.right = this.sv[i].x;
        		if(this.sv[i].y < this.top)
        			this.top = this.sv[i].y;
        		if(this.sv[i].y > this.bottom)
        			this.bottom = this.sv[i].y;
        	}

        	this.top = Math.floor(this.top);
        	this.bottom = Math.ceil(this.bottom);
        	this.left = Math.floor(this.left);
        	this.right = Math.ceil(this.right);
            
            var c = 0;
        	for(var i = 0; i < 3; i++)
        		c += this.sv[i].x*(this.sv[(i+1)%3].y - this.sv[(i+2)%3].y);

        	lines = [];
        	if(c > 0)
        	{	
        		lines.push(new Engine.Line(this.sv[0],this.sv[2]));
        		lines.push(new Engine.Line(this.sv[2],this.sv[1]));
        		lines.push(new Engine.Line(this.sv[1],this.sv[0]));
        	}
        	else
        	{
        		lines.push(new Engine.Line(this.sv[0],this.sv[1]));
        		lines.push(new Engine.Line(this.sv[1],this.sv[2]));
        		lines.push(new Engine.Line(this.sv[2],this.sv[0]));
        	}
        }
    };
})();

